<?php

/**
 * 公共方法
 */

use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Hyperf\Logger\LoggerFactory;
use Hyperf\Server\ServerFactory;
use Hyperf\Utils\ApplicationContext;
use Psr\Http\Message\ServerRequestInterface;
use Swoole\Websocket\Frame;
use Swoole\WebSocket\Server as WebSocketServer;
use Service\Code\Normal;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\DbConnection\Db;
use Service\AppService\SystemCacheConfigService;

/**
 *@des      一维数组生成多维数组
 *@param    array  $arr   数组
 *@param    int    $pid   父id
 *@param    string $id_k  主键字段
 *@param    string $pid_k 父id字段
 *@return   array
 */
if (!function_exists('tree')) {
    function tree($arr, $pid, $id_k, $pid_k)
    {
        $tree  =   array();
        foreach ($arr as $k => $v) {
            if ($v[$pid_k] == $pid) {
                unset($arr[$k]);
                $temp         =   $v;
                $temp['son']  =   tree($arr, $v[$id_k], $id_k, $pid_k);

                if(!$temp['son']){
                    $temp['son'] = null;
                    unset($temp['son']);
                }
                $tree[]       =   $temp;
            }
        }
        return $tree;
    }
}

if (!function_exists('checkFields')) {
    /**
     * 过滤特殊字符
     * 防止sql注入
     */
    function checkFields( $string = '' ) {
        $string = strip_tags($string);
        $string = addslashes($string);
        $string = php_remove_html($string);
        $string = dowith_sql($string);
        return $string;
    }
}

if (!function_exists('php_remove_html')) {
    /**
     * 去除相关html标签
     * @param $str
     */
    function php_remove_html( $str = '') {
        $farr = array(
            "/s /",
            "/<(/?)(script|i?frame|style|html|body|title|link|meta|?|%)([^>]*?)>/isU",
            "/(<[^>]*)on[a-zA-Z] s*=([^>]*>)/isU",
        );
        $tarr = array(
            " ",
            "＜\1\2\3＞",           //如果要直接清除不安全的标签，这里可以留空
            "\1\2",
        );
        $str = str_replace($farr,$tarr,$str);
        return $str;
    }
}

if (!function_exists('dowith_sql')) {
    /**
     * 过滤sql
     * @param string $str
     * @return mixed
     */
    function dowith_sql( $str = '' ) {
        $str = str_replace("and","",$str);
        $str = str_replace("execute","",$str);
        $str = str_replace("update","",$str);
        $str = str_replace("count","",$str);
        $str = str_replace("chr","",$str);
        $str = str_replace("mid","",$str);
        $str = str_replace("master","",$str);
        $str = str_replace("truncate","",$str);
        $str = str_replace("char","",$str);
        $str = str_replace("declare","",$str);
        $str = str_replace("select","",$str);
        $str = str_replace("create","",$str);
        $str = str_replace("delete","",$str);
        $str = str_replace("insert","",$str);
        $str = str_replace("'","",$str);
        $str = str_replace('"',"",$str);
        $str = str_replace(" ","",$str);
        $str = str_replace("or","",$str);
        $str = str_replace("=","",$str);
        $str = str_replace(" ","",$str);
        return $str;
    }   
}

if (!function_exists('get13TimeStamp')) {
    /**
     * 获取13位的时间戳
     * @return int
     */
    function get13TimeStamp() {
        list($t1, $t2) = explode(' ', microtime());
        return $t2 . ceil($t1 * 1000);
    }
}

if (!function_exists('getRandChar')) {
    /**
     * @param Int $length 字符串长度
     * @return string
     */
    function getRandChar($length,$type = 'numeric')
    {
        $str = null;
        switch ($type){
            case 'numeric':
                $strPol = "0123456789";
                break;
            default:
                $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
        }
        $max = strlen($strPol) - 1;
    
        for ($i = 0;
        $i < $length;
        $i++) {
            $str .= $strPol[rand(0, $max)];
        }
    
        return $str;
    }
}

if (!function_exists('uuid4')) {
    /**
     * 生成唯一标志uuid version 4
     * 标准的UUID格式为：xxxxxxxx-xxxx-xxxx-xxxxxx-xxxxxxxxxx(8-4-4-4-12)
     * @return string
     */
    function uuid4()
    {
        $chars = md5(uniqid(mt_rand(), true));
        return substr ($chars, 0, 8 ) . '-'
                . substr ( $chars, 8, 4 ) . '-'
                . substr ( $chars, 12, 4 ) . '-'
                . substr ( $chars, 16, 4 ) . '-'
                . substr ( $chars, 20, 12 );
    }
}

if (!function_exists('floatCheck')) {
    function floatCheck( $float = 0.00 ){
        $money_reg = '/^[0-9]+(.[0-9]{1,2})?$/';
        return preg_match($money_reg, $float);
    }
}

if (!function_exists('intNumberChcek')) {
    function intNumberChcek( $int = 0 ){
        return preg_match('/^[1-9][0-9]*$/', $int);
    }
}

if (!function_exists('checkOnlyDC')) {
    /**
     * 检查只包含数字和字母
     * @param string $string
     * @return number
     */
    function checkOnlyDC( $string = '' ){
        return preg_match('/^[a-zA-Z0-9-_]+$/u', $string);
    }
}

if (!function_exists('checkOrderSn')) {
    /**
     * 检查订单编号是否有效
     * @param string $string
     */
    function checkOrderSn(  $string = '' ) {
        return checkOnlyDC($string) && mb_strlen($string,'utf-8') <= 50 ;
    }
}

if (!function_exists('checkPhone')) {
    /**
     * 验证电话号码
     * @param string $string
     */
    function checkPhone( $string = '' ) {
        return preg_match('/^1[3456789]\d{9}$/ims', $string);
    }
}

if (!function_exists('checkCallPhone')) {
    /**
     * 验证固定号码
     * @param string $string
     */
    function checkCallPhone( $string = '' ) {
        return preg_match('/^(0\d{2,3})?(\d{7,8})$/ims', $string);
    }
}

if (!function_exists('checkGoodsName')) {
    /**
     * 检查商品名称
     * @param string $string
     */
    function checkGoodsName( $string = '' ) {
        return mb_strlen($string,'utf-8') <= 120 ;
    }
}

if (!function_exists('checkDateFormat')) {
    /**
     * 检查日期
     * @param string $date
     * @return boolean
     */
    function checkDateFormat($date)
    {
        //匹配日期格式
        if (preg_match ("/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/", $date, $parts))
        {
            //检测是否为日期
            if(checkdate($parts[2],$parts[3],$parts[1]))
                return true;
                else
                    return false;
        }
        else
            return false;
    }
}

if (!function_exists('checkUserPassWord')) {
    /**
     * 检测密码
     * @param $string
     * @return number
     */
    function checkUserPassWord( $string = null ){
        //return preg_match('/^[0-9a-zA-Z]{6,16}$/', $string);
        return preg_match('/^\S{6,16}$/', $string);
    }
}

if (!function_exists('fetchRepeatMemberInArray')) {
    //判断数组中是否存在重复的数据
    function fetchRepeatMemberInArray($array)
    {
        // 获取去掉重复数据的数组
        $unique_arr = array_unique ( $array );
        // 获取重复数据的数组
        $repeat_arr = array_diff_assoc ( $array, $unique_arr );
        return $repeat_arr;
    }
}

if (!function_exists('checkRealName')) {
    /**
     * 验证真实姓名
     */
    function checkRealName( $string ) {
    
        $ret = true;
        //中文+身份证允许有.
        if (!preg_match('/^[\x{4e00}-\x{9fa5}]+[·•]?[\x{4e00}-\x{9fa5}]+$/u', $string)) {
            return true;
        }
    
        $strLen = mb_strlen($string,'utf-8');
        //字符长度2到8之间
        if ($strLen < 2 || $strLen > 15) {
            return false;
        }
    
        return $ret;
    }
}

if (!function_exists('checkIdCard')) {
    /**
     * 验证身份证
     * @param unknown $id
     * @return boolean
     */
    function checkIdCard( $vStr ) {
        $vCity = array(
            '11','12','13','14','15','21','22',
            '23','31','32','33','34','35','36',
            '37','41','42','43','44','45','46',
            '50','51','52','53','54','61','62',
            '63','64','65','71','81','82','91'
        );
        if (!preg_match('/^([\d]{17}[xX\d]|[\d]{15})$/', $vStr)) return false;
        if (!in_array(substr($vStr, 0, 2), $vCity)) return false;
        $vStr = preg_replace('/[xX]$/i', 'a', $vStr);
        $vLength = strlen($vStr);
        if ($vLength == 18) {
            $vBirthday = substr($vStr, 6, 4) . '-' . substr($vStr, 10, 2) . '-' . substr($vStr, 12, 2);
        } else {
            $vBirthday = '19' . substr($vStr, 6, 2) . '-' . substr($vStr, 8, 2) . '-' . substr($vStr, 10, 2);
        }
        if (date('Y-m-d', strtotime($vBirthday)) != $vBirthday) return false;
        if ($vLength == 18) {
            $vSum = 0;
            for ($i = 17 ; $i >= 0 ; $i--) {
                $vSubStr = substr($vStr, 17 - $i, 1);
                $vSum += (pow(2, $i) % 11) * (($vSubStr == 'a') ? 10 : intval($vSubStr , 11));
            }
            if($vSum % 11 != 1) return false;
        }
        return true;
    }   
}

/**
 * 容器实例
 */
if (!function_exists('container')) {
    function container()
    {
        return ApplicationContext::getContainer();
    }
}

/**
 * redis 客户端实例
 */
if (!function_exists('redis')) {
    function redis()
    {
        return container()->get(Redis::class);
    }
}

/**
 * server 实例 基于 swoole server
 */
if (!function_exists('server')) {
    function server()
    {
        return container()->get(ServerFactory::class)->getServer()->getServer();
    }
}

/**
 * websocket frame 实例
 */
if (!function_exists('frame')) {
    function frame()
    {
        return container()->get(Frame::class);
    }
}

/**
 * websocket 实例
 */
if (!function_exists('websocket')) {
    function websocket()
    {
        return container()->get(WebSocketServer::class);
    }
}

/**
 * 缓存实例 简单的缓存
 */
if (!function_exists('cache')) {
    function cache()
    {
        return container()->get(Psr\SimpleCache\CacheInterface::class);
    }
}

/**
 * 控制台日志
 */
if (!function_exists('stdLog')) {
    function stdLog()
    {
        return container()->get(StdoutLoggerInterface::class);
    }
}

/**
 * 文件日志
 */
if (!function_exists('logger')) {
    function logger($name = 'hyperf',$group = 'default')
    {
        return container()->get(LoggerFactory::class)->make($name,$group);
    }
}

/**
 *
 */
if (!function_exists('request')) {
    function request()
    {
        return container()->get(ServerRequestInterface::class);
    }
}

/**
 *
 */
if (!function_exists('response')) {
    function response()
    {
        return container()->get(ResponseInterface::class);
    }
}

/**
 *获取客户端ip地址
 */
if (!function_exists('getIp')) {
    function getIp()
    {
        $request = ApplicationContext::getContainer()->get(RequestInterface::class);
        $headers = $request->getHeaders();
        if(isset($headers['x-forwarded-for'][0]) && !empty($headers['x-forwarded-for'][0])) {
            return $headers['x-forwarded-for'][0];
        } elseif (isset($headers['x-real-ip'][0]) && !empty($headers['x-real-ip'][0])) {
            return $headers['x-real-ip'][0];
        }
        
        $serverParams = $request->getServerParams();
        return $serverParams['remote_addr'] ?? '';
        
        /* $serverParams = container()->get(ServerRequestInterface::class)->getServerParams();
        if(isset($serverParams['http_client_ip'])){
            return $serverParams['http_client_ip'];
        }elseif(isset($serverParams['http_x_real_ip'])){
            return $serverParams['http_x_real_ip'];
        }elseif(isset($serverParams['http_x_forwarded_for'])){
            //部分CDN会获取多层代理IP，所以转成数组取第一个值
            $arr = explode(',',$serverParams['http_x_forwarded_for']);
            return $arr[0];
        }else{
            return $serverParams['remote_addr'];
        } */
    }
}

/**
 * 自定义tree
 * 省市区
 */
if (!function_exists('treeKeys')) {
    function treeKeys($arr, $pid, $id_k, $pid_k)
    {
        $tree  =   array();
        foreach ($arr as $k => $v) {
            if ($v[$pid_k] == $pid) {
                unset($arr[$k]);
                $temp         =   $v;
                $temp['list']  =   treeKeys($arr, $v[$id_k], $id_k, $pid_k);

                if(!$temp['list']){
                    unset($temp['list']);
                }
                $tree[$v[$id_k]]       =   $temp;
            }
        }
        return $tree;
    }
}

/**
 * 获取微秒数
 */
if (!function_exists('MsecTime')) {
    function MsecTime()
    {
        list($msec, $sec) = explode(' ', microtime());
        $msectime = (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
        return $msectime;
    }
}

/**
 * 协程方式调用
 * @param string $class
 * @param string $method
 * @param array $param
 */
function callCoroutineApi( string $class , string $method , array $parameters = [] )
{
    if( ! ApplicationContext::hasContainer($class) ) {
        return Normal::returnCode(Normal::FAIL,"class file 【{$class}】 not existed!");
    }
    
    $classObj = container()->get($class);
    return $classObj->{$method}($parameters);
}

/**
 * 对价格进行向上或向下取整
 *  $price    价格
 *  $decimal  保留小数位数
 * $type 1：向上 2：向下
 */
function upDecimal($price, $decimal = 2, $type = 1){
    //取整入1
    //return  sprintf("%.2f",$price);
    if (empty($decimal)) {
        return ceil($price);
    }
    $price2 =  explode('.', $price);
    $price1 = $price2[1] ?? 0;
    $price0 = $price2[0] ?? 0;
    $sublen = strlen($price1);
    if ($sublen < $decimal) {
        $decimal = $sublen;
    }
    //没有小数入1
    if (empty($price1)) {
        return ceil($price);
    }
    $subnum = bcsub($sublen, $decimal);
    //计算小数
    $powsub = bcpow(10, $subnum);
    $price1 = bcdiv($price1, $powsub, $sublen);
    $price1 = ceil($price1);
    $powint = bcpow(10, $decimal);
    $price1 = bcdiv($price1, $powint, $decimal);
    //返回结果
    return bcadd($price0, $price1, $decimal);
}

function getSignContent($data): string
{
    $buff = '';
    foreach ($data as $k => $v) {
        $buff .= ($k != 'sign' && $v != '' && !is_array($v)) ? $k.'='.$v.'&' : '';
    }
    return trim($buff, '&');
}

function getSID()
{
    return env('SID') ?? 1 ;
}


/**
 * 获取分组功能
 * @param array $data
 */
function getArrayGroupData( array $data ,string $_fileds )
{
    if( empty($data) ) {
        return [];
    }

    $temp = [];
    foreach ($data as $item)
    {
        $temp[$item[$_fileds]][] = $item;
        unset($item);
    }

    return $temp;
}


/**
 *
 * 产生随机字符串，不长于32位
 * @param int $length
 * @return string|产生的随机字符串
 */
function getNonceStr($length = 32)
{
    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    $str ="";
    for ( $i = 0; $i < $length; $i++ )  {
        $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
    }
    return $str;
}

/**
 * @隐藏用户手机号
 * @param    string $mobile
 * @return   string
 */
if (!function_exists('hide_mobile')) {
    function hide_mobile(string $mobile = ''):string
    {
        return str_replace(substr($mobile, 3, 4), '****', $mobile);
    }
}
/**
 * 是否是调试模式
 */
function isDebugMode()
{
    return env('IS_DEBUG_MODE');
}


/**
 * 校验用户手机号码
 * @param string $mobile
 */
function checkUserMobileReg(string $mobile)
{
    // return preg_match(USER_MOBILE_REG, $mobile);
}

/**
 * 获取所有子级
 * @param    array  $arr   数组
 * @param    int    $pid   父id
 * @param    string $id_k  主键字段
 * @param    string $pid_k 父id字段
 * @return   array
 */
if (!function_exists('all_sub')) {
    function all_sub($arr, $pid, $id_k, $pid_k)
    {
        $son = [];
        foreach ($arr as $k => $v) {
            if ($v[$pid_k] == $pid) {
                unset($arr[$k]);
                $son[]    = $v;
                $sub_son  = all_sub($arr, $v[$id_k], $id_k, $pid_k);
                $son      = array_merge($son, $sub_son);
            }
        }
        return $son;
    }
}

/**
 * 根据二维数组某个字段的值查找数组,只适用于不重复的指定键值
 * @param $array
 * @param $index //键名
 * @param $value //值
 * @return array
 */
function filterByValue (array $array, string $index, string $value){
    $newarray = [];
    if(is_array($array) && count($array) > 0)
    {
        foreach(array_keys($array) as $key){
            $temp[$key] = $array[$key][$index];
            if ($temp[$key] == $value){
                $newarray = $array[$key];
            }
        }
    }
    return $newarray;
}

function pre_image_url(){
    return 'https://indoorbuy.oss-cn-hangzhou.aliyuncs.com/';
}

function pic_level(){
    return array(//默认分级
                 'big'=>'?x-oss-process=image/crop,x_0,y_0,w_1000,h_1000,g_se',//大图：以宽度和高度裁剪，裁剪最长为1000pc
                 'mid'=>'?x-oss-process=image/crop,x_0,y_0,w_500,h_500,g_se',//中图：以宽度和高度裁剪，裁剪最长为500pc
                 'small'=>'?x-oss-process=image/crop,x_0,y_0,w_200,h_200,g_se',//小图：以宽度和高度裁剪，裁剪最长为200pc
                 'big_resize'=>'?x-oss-process=image/resize,m_lfit,h_1000,w_1000',//大图：以宽度高度缩放，最大值为1000pc
                 'mid_resize'=>'?x-oss-process=image/resize,m_lfit,h_750,w_750',//中图：以宽度高度缩放，最大值为500pc
                 'small_resize'=>'?x-oss-process=image/resize,m_lfit,h_360,w_360',//以宽度高度缩放，最大值为200pc
    );
}

/**
 * 获取多个like and 情况
 * @param string $hacks
 * @param string $string
 * @param string $field
 * @return boolean|string
 */
function getMultiLikeByString(string $hacks,string $string,string $field)
{
    if( strpos($string, $hacks) === false ) {
        return false;
    }
    
    $explodes = explode("'", $string);
    $explodes = array_filter($explodes);
    if( empty($explodes) ) {
        return false;
    }
    
    $_multi_like = [];
    foreach($explodes as $search)
    {
        $_multi_like[] = "{$field} like '%{$search}%'";
    }

    return "(". \implode(" AND ",$_multi_like) .")";
}

/**
 *  获取是否tomo云仓 模式 
 */
function getIsTomoMode()
{
    $config = SystemCacheConfigService::instance()->getCacheInfoBySystemCode('tomo_config');
    return !empty($config['is_open_tomo']) && $config['is_open_tomo'] == 1 ? true : false;
}


/**
 * 检查过滤特殊字符参数
 * @param string $string
 */
function filterParam($string)
{
    $string = (string)$string;
    $string = addslashes($string);
    $string = htmlentities($string);
    $string = htmlspecialchars($string);
    return $string;
}

/**
 * 反转特殊字符
 * @param string $string
 */
function filterReverseParam($string)
{
    $string = (string)$string;
    $string = htmlspecialchars_decode($string);
    $string = html_entity_decode($string);
    $string = stripcslashes($string);
    return $string;
}